package io.wit.tool;

import com.alibaba.fastjson.JSONObject;
import io.wit.config.ConfigFile;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class ToolClient{

    private static Logger logger = LoggerFactory.getLogger(ToolClient.class);

    /**
     * 查询时得到的数据为空返回的json字符串
     * @作者 田应平
     * @返回值类型 String
     * @创建时间 2017年1月11日 下午9:40:21
     * @QQ号码 444141300
     * @主页 http://www.fwtai.com
    */
    private static String queryEmpty(){
        return createJson(ConfigFile.code201,ConfigFile.msg201);
    }

    /**
     * 生成json字符串对象,直接采用JSONObject封装,执行效率会更高;适用于为增、删、改操作时,判断当前的rows是否大于0来确定是否操作成功,一般在service调用,偷懒的人可以使用本方法
     * @param rows 执行后受影响的行数
     * @用法 解析后判断data.code == AppKey.code.code200即可操作
     * @作者 田应平
     * @创建时间 2016年12月25日 下午5:44:23
     * @QQ号码 444141300
     * @官网 http://www.fwtai.com
    */
    public static String executeRows(final int rows){
        if(rows > 0){
            return jsonData(ConfigFile.msg200,rows);
        }else{
            return createJsonFail(ConfigFile.msg199);
        }
    }

    /**
     * 操作成功生成json字符串对象,失败信息是ConfigFile.msg199,直接采用JSONObject封装,执行效率会更高;适用于为增、删、改操作,一般在service调用
     * @param
     * @作者 田应平
     * @QQ 444141300
     * @创建时间 2020/1/19 11:31
    */
    public static String executeRows(final int rows,final String success){
        if(rows > 0){
            return jsonData(success,rows);
        }else{
            return createJsonFail(ConfigFile.msg199);
        }
    }

    /**
     * code=200的成功json数据格式
     * @param msg code=200时提示的信息
     * @param data key的data的数据对象
     * @作者 田应平
     * @QQ 444141300
     * @创建时间 2021/3/31 14:28
    */
    protected static String jsonData(final String msg,final Object data){
        final JSONObject json = new JSONObject(3);
        json.put(ConfigFile.code,ConfigFile.code200);
        json.put(ConfigFile.msg,msg);
        json.put(ConfigFile.data,data);
        return json.toJSONString();
    }

    /**
     * 生成自定义的json对象,直接采用JSONObject封装,执行效率会更高;适用于为增、删、改操作,一般在service调用
     * @param rows 执行后受影响的行数
     * @param success 执行成功的提示消息
     * @param failure 执行失败的提示消息
     * @作者 田应平
     * @创建时间 2016年12月25日 下午5:50:22
     * @QQ号码 444141300
     * @官网 http://www.fwtai.com
    */
    public static String executeRows(final int rows,final String success,final String failure){
        if(rows > 0){
            return jsonData(success,rows);
        }else{
            return createJsonFail(failure);
        }
    }

    /**
     * 生成json格式字符串,code和msg的key是固定的,直接采用JSONObject封装,执行效率会更高,用于增、删、改、查操作,一般在service层调用
     * @作者 田应平
     * @返回值类型 返回的是json字符串,内部采用JSONObject封装
     * @用法 解析后判断data.code == AppKey.code.code200即可处理操作
     * @创建时间 2016年12月25日 18:11:16
     * @QQ号码 444141300
     * @param code 相关参数协议
     * @主页 http://www.fwtai.com
    */
    public static String createJson(final int code,final String msg){
        final JSONObject json = new JSONObject(2);
        json.put(ConfigFile.code,code);
        json.put(ConfigFile.msg,msg);
        return json.toJSONString();
    }

    /**
     * 生成code为199的json格式数据且msg是提示信息
     * @param
     * @作者 田应平
     * @QQ 444141300
     * @创建时间 2019/7/29 15:00
    */
    public static String createJsonFail(final String msg){
        return createJson(ConfigFile.code199,msg);
    }

    //无操作权限|未授权
    public static String unauthorized(){
        return createJson(ConfigFile.code401,ConfigFile.msg401);
    }

    public static String invalidToken(){
        return createJson(205,"未登录或登录超时");
    }

    public static String exceptionJson(){
        return createJson(500,"系统出现错误");
    }

    public static void responseJson(final String json,final HttpServletResponse response){
        response.setContentType("text/html;charset=utf-8");
        response.setHeader("Cache-Control","no-cache");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.write(json);
            writer.flush();
        }catch (IOException e){
        }finally{
            if(writer != null){
                writer.close();
                writer = null;
            }
        }
    }

    public static String queryJson(final Object object){
        if(object == null || object.toString().trim().length() <= 0){
            return queryEmpty();
        }
        if (object instanceof Exception) {
            return exceptionJson();
        }
        if(object instanceof Map<?,?>){
            final Map<?,?> map = (Map<?,?>) object;
            if(map.size() <= 0){
                queryEmpty();
            }else {
                return jsonData(ConfigFile.msg200,object);
            }
        }
        final JSONObject json = new JSONObject(3);
        if(object instanceof List<?>){
            final List<?> list = (List<?>) object;
            if(list.size() <= 0){
                return queryEmpty();
            }else {
                if (list.get(0) == null){
                    return queryEmpty();
                }else {
                    json.put(ConfigFile.code,ConfigFile.code200);
                    json.put(ConfigFile.msg,ConfigFile.msg200);
                    json.put(ConfigFile.data,object);
                    json.put(ConfigFile.record,((List<?>) object).size());
                    final String jsonObj = json.toJSONString();
                    final JSONObject j = JSONObject.parseObject(jsonObj);
                    final String listData = j.getString(ConfigFile.data);
                    if (listData.equals("[{}]")){
                        return queryEmpty();
                    }
                    return jsonObj;
                }
            }
        }
        if(String.valueOf(object).toLowerCase().equals("null") || String.valueOf(object).replaceAll("\\s*", "").length() == 0){
            return queryEmpty();
        }else {
            json.put(ConfigFile.code,ConfigFile.code200);
            json.put(ConfigFile.msg,ConfigFile.msg200);
            json.put(ConfigFile.data,object);
            final String jsonObj = json.toJSONString();
            final JSONObject j = JSONObject.parseObject(jsonObj);
            final String obj = j.getString(ConfigFile.data);
            if (obj.equals("{}")){
                return queryEmpty();
            }
            return jsonObj;
        }
    }

    public static UploadObject uploadFile(final HttpServletRequest request,final String baseDir,final String prefixType,final Integer limit,final boolean verify){
        return uploadFile(request,baseDir,prefixType,false,limit,verify);
    }

    private static UploadObject uploadFile(final HttpServletRequest request,final String baseDir,final String prefixType,final boolean temporary,final Integer limit,final boolean verify){
        final UploadObject uploadObject = new UploadObject();
        MultipartHttpServletRequest mhsr = null;
        try {
            mhsr = (MultipartHttpServletRequest) request;
        } catch (Exception e){
            if(verify){
                uploadObject.setErrorMsg("请上传文件");
                return uploadObject;
            }
        }
        final Map<String,MultipartFile> map = mhsr.getFileMap();
        if(verify){
            if(map == null || map.size() <=0){
                uploadObject.setErrorMsg("请选择上传文件");
                return uploadObject;
            }
        }
        if(limit != null && limit > 0){
            if(map.size() > limit){
                uploadObject.setErrorMsg("文件数量已超过限制");
                return uploadObject;
            }
        }
        final DiskFileItemFactory fac = new DiskFileItemFactory();
        final ServletFileUpload upload = new ServletFileUpload(fac);
        final ArrayList<UploadFile> files = new ArrayList<UploadFile>();
        try {
            upload.setHeaderEncoding("utf-8");
            mhsr.setCharacterEncoding("utf-8");
            boolean bl = false;
            for(final String key : map.keySet()){
                final MultipartFile mf = mhsr.getFile(key);
                if(mf.getSize() > 1024*1024*15L){//15mb
                    bl = true;
                    break;
                }
                final String originalName = mf.getOriginalFilename();
                final String extName = originalName.substring(originalName.lastIndexOf("."));
                final String fileName = ToolString.getIdsChar32() + extName;
                final String dayDir = temporary ? (prefixType + "/") : (prefixType + "/" + new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/");
                final File fileDir = new File(baseDir + dayDir);
                if(!fileDir.exists()){
                    fileDir.mkdirs();
                }
                final String fullPath = (baseDir + dayDir + fileName).replaceAll("//","/");
                mf.transferTo(new File(fullPath));
                final UploadFile uploadFile = new UploadFile();
                uploadFile.setUrlFile(dayDir + fileName);
                uploadFile.setOriginalName(originalName);
                uploadFile.setFullPath(fullPath);
                uploadFile.setFileName(fileName);
                uploadFile.setBasePath(baseDir);
                uploadFile.setName(key);
                files.add(uploadFile);
            }
            if(bl){
                for(int i = 0; i < files.size(); i++){
                    delFileByThread(files.get(i).getFullPath());
                }
                uploadObject.setErrorMsg("操作失败,某个文件过大");
                return uploadObject;
            }
            if(files.size() > 0){
                uploadObject.setListFiles(files);
            }
            return uploadObject;
        } catch (Exception e) {
            for(int i = 0; i < files.size(); i++){
                delFileByThread(files.get(i).getFullPath());
            }
            uploadObject.setErrorMsg("操作失败,处理文件失败");
            return uploadObject;
        }
    }

    public static void delFileByThread(final String filePath) {
        try {
            new Thread(){
                public void run() {
                    final File file = new File(filePath);
                    if(file.isFile()){
                        file.delete();
                    }
                }
            }.start();
        } catch (Exception e){}
    }

    public static String validateField(final Map<String,?> params,final String... fields){
        if(params == null || params.size() <= 0) return jsonValidateField();
        for (final String value : fields){
            final Object object = params.get(value);
            if(object == null){
                logger.warn(value+"参数的值为空");
                return jsonValidateField();
            }else{
                final boolean bl = checkNull(String.valueOf(object));
                if(bl){
                    return jsonValidateField();
                }
            }
        }
        return null;
    }

    public static String jsonValidateField(){
        return createJson(ConfigFile.code199,"请求参数有误");
    }

    private static boolean checkNull(final String value){
        if(value.length() <= 0)return true;
        if(value.equals("_"))return true;
        if(value.equalsIgnoreCase("undefined"))return true;
        if(value.equalsIgnoreCase("null"))return true;
        return false;
    }

    public static HashMap<String,String> getFormParams(final HttpServletRequest request){
        final HashMap<String,String> params = new HashMap<String,String>();
        final Enumeration<String> paramNames = request.getParameterNames();
        while(paramNames.hasMoreElements()){
            final String key = paramNames.nextElement();
            if(key.equals("_"))continue;
            String value = request.getParameter(key);
            if(value != null && value.length() >0){
                value = value.trim();
                if(checkNull(value))
                    continue;
                params.put(key,value);
            }
        }
        return params;
    }

    public static <T> T mapToBean(final HashMap<String,String> map,final Class<T> cls){
        return JSONObject.parseObject(JSONObject.toJSONString(map),cls);
    }

    /**
     * 利用反射从表单构建实体对象,做业务之前先做判断是否为空再处理业务
     * @用法 final UserEntity user = ToolEntity.getEntity(request,UserEntity.class);
     * @param request
     * @param clszz 目标实体
     * @作者 田应平
     * @QQ 444141300
     * @创建时间 2021/5/30 11:50
    */
    public static <T> T getEntity(final HttpServletRequest request,final Class<T> clszz){
        final Field[] fields = clszz.getDeclaredFields();//获取所有的属性
        try {
            final T object = clszz.newInstance();//实例化对象
            for(final Field field : fields){
                field.setAccessible(true);
                final String type = field.getType().getSimpleName();
                final String name = field.getName();
                final String value = request.getParameter(name);
                switch (type){
                    case "Float":
                        if(value != null && value.length() >0){
                            field.set(object,Float.parseFloat(value));
                        }
                        break;
                    case "Double":
                        if(value != null && value.length() >0){
                            field.set(object,Double.parseDouble(value));
                        }
                        break;
                    case "Integer":
                        if(value != null && value.length() >0){
                            field.set(object,Integer.parseInt(value));
                        }
                        break;
                    case "Long":
                        if(value != null && value.length() >0){
                            field.set(object,Long.parseLong(value));
                        }
                        break;
                    default:
                        if(value != null && value.length() >0){
                            field.set(object,value);
                        }
                        break;
                }
            }
            return object;
        } catch (final Exception e){
            e.printStackTrace();
        }
        return null;
    }
}